using System;
using System.Collections.Generic;
using System.Text;
using FlatRedBall.AI.Pathfinding;
using FlatRedBall.Graphics.Model;

using FlatRedBall.Input;
using FlatRedBall.Utilities;

using FlatRedBall.Instructions;
using FlatRedBall.Math.Splines;
using BitmapFont = FlatRedBall.Graphics.BitmapFont;
using Cursor = FlatRedBall.Gui.Cursor;
using GuiManager = FlatRedBall.Gui.GuiManager;
// Generated Usings
using MultiplayerTD.Screens;
using Matrix = Microsoft.Xna.Framework.Matrix;
using FlatRedBall;
using FlatRedBall.Graphics;
using FlatRedBall.Math;
using FlatRedBall.Gui;
using FlatRedBall.Broadcasting;
using MultiplayerTD.Entities;
using MultiplayerTD.Factories;
using FlatRedBall;
using FlatRedBall.ManagedSpriteGroups;
using FlatRedBall.Graphics.Animation;

#if XNA4
using Color = Microsoft.Xna.Framework.Color;
#else
using Color = Microsoft.Xna.Framework.Graphics.Color;
#endif

#if FRB_XNA || SILVERLIGHT
using Keys = Microsoft.Xna.Framework.Input.Keys;
using Vector3 = Microsoft.Xna.Framework.Vector3;
using Texture2D = Microsoft.Xna.Framework.Graphics.Texture2D;
#endif

#if FRB_XNA && !MONODROID
using Model = Microsoft.Xna.Framework.Graphics.Model;
#endif

namespace MultiplayerTD.Entities
{
	public partial class Button : PositionedObject, IDestroyable, IWindow, IVisible
	{
        // This is made global so that static lazy-loaded content can access it.
        public static string ContentManagerName
        {
            get;
            set;
        }

		// Generated Fields
		#if DEBUG
		static bool HasBeenLoadedWithGlobalContentManager = false;
		#endif
		public enum VariableState
		{
			Uninitialized, //This exists so that the first set call actually does something
			Regular, 
			Pressed, 
			Disabled, 
			Hover
		}
		static object mLockObject = new object();
		static bool mHasRegisteredUnload = false;
		static bool IsStaticContentLoaded = false;
		private static AnimationChainList AnimationChainListFile;
		private static Scene SceneFile;
		
		private SpriteFrame SpriteFrameInstance;
		private MultiplayerTD.Entities.TextArial TextArialInstance;
		public string SpriteFrameInstanceCurrentChainName
		{
			get
			{
				return SpriteFrameInstance.CurrentChainName;
			}
			set
			{
				SpriteFrameInstance.CurrentChainName = value;
			}
		}
		public string DisplayText
		{
			get
			{
				return TextArialInstance.DisplayText;
			}
			set
			{
				TextArialInstance.DisplayText = value;
			}
		}
		public float ScaleX
		{
			get
			{
				return SpriteFrameInstance.ScaleX;
			}
			set
			{
				SpriteFrameInstance.ScaleX = value;
			}
		}
		public int Index { get; set; }
		public bool Used { get; set; }
		public event EventHandler BeforeVisibleSet;
		public event EventHandler AfterVisibleSet;
		protected bool mVisible = true;
		public virtual bool Visible
		{
			get
			{
				return mVisible;
			}
			set
			{
				if (BeforeVisibleSet != null)
				{
					BeforeVisibleSet(this, null);
				}
				mVisible = value;
				SpriteFrameInstance.Visible = mVisible;
				TextArialInstance.Visible = mVisible;
				if (AfterVisibleSet != null)
				{
					AfterVisibleSet(this, null);
				}
			}
		}
		protected Layer LayerProvidedByContainer = null;

        public Button(string contentManagerName) :
            this(contentManagerName, true)
        {
        }


        public Button(string contentManagerName, bool addToManagers) :
			base()
		{
			// Don't delete this:
            ContentManagerName = contentManagerName;
            InitializeEntity(addToManagers);

		}

		protected virtual void InitializeEntity(bool addToManagers)
		{
			// Generated Initialize
			LoadStaticContent(ContentManagerName);
			SpriteFrameInstance = SceneFile.SpriteFrames.FindByName("AnimationChainListFile").Clone();
			TextArialInstance = new MultiplayerTD.Entities.TextArial(ContentManagerName, false);
			TextArialInstance.Name = "TextArialInstance";
			this.Push += OnPush;
			this.Click += OnClick;
			
			PostInitialize();
			if (addToManagers)
			{
				AddToManagers(null);
			}


		}

// Generated AddToManagers
		public virtual void AddToManagers (Layer layerToAddTo)
		{
			LayerProvidedByContainer = layerToAddTo;
			SpriteManager.AddPositionedObject(this);
			GuiManager.AddWindow(this);
			AddToManagersBottomUp(layerToAddTo);
			CustomInitialize();
		}

		public virtual void Activity()
		{
			// Generated Activity
			mIsPaused = false;
			
			TextArialInstance.Activity();
			CustomActivity();
			
			// After Custom Activity
		}

		public virtual void Destroy()
		{
			// Generated Destroy
			SpriteManager.RemovePositionedObject(this);
			GuiManager.RemoveWindow(this);
			if (SpriteFrameInstance != null)
			{
				SpriteManager.RemoveSpriteFrame(SpriteFrameInstance);
			}
			if (TextArialInstance != null)
			{
				TextArialInstance.Destroy();
			}
			


			CustomDestroy();
		}

		// Generated Methods
public virtual void PostInitialize ()
{
	SpriteFrameInstanceCurrentChainName = "Regular";
	DisplayText = "Text";
	ScaleX = 64f;
	X = 0f;
	Y = 0f;
	Z = 0f;
	TextArialInstance.DisplayText = "Text";
	TextArialInstance.Z = 1f;
}
public virtual void AddToManagersBottomUp (Layer layerToAddTo)
{
	// We move this back to the origin and unrotate it so that anything attached to it can just use its absolute position
	float oldRotationX = RotationX;
	float oldRotationY = RotationY;
	float oldRotationZ = RotationZ;
	
	float oldX = X;
	float oldY = Y;
	float oldZ = Z;
	
	X = 0;
	Y = 0;
	Z = 0;
	RotationX = 0;
	RotationY = 0;
	RotationZ = 0;
	SpriteManager.AddToLayer(SpriteFrameInstance, layerToAddTo);
	if (SpriteFrameInstance.Parent == null)
	{
		SpriteFrameInstance.AttachTo(this, true);
	}
	TextArialInstance.AddToManagers(layerToAddTo);
	TextArialInstance.DisplayText = "Text";
	TextArialInstance.Z = 1f;
	if (TextArialInstance.Parent == null)
	{
		TextArialInstance.AttachTo(this, true);
	}
	X = oldX;
	Y = oldY;
	Z = oldZ;
	RotationX = oldRotationX;
	RotationY = oldRotationY;
	RotationZ = oldRotationZ;
}
public virtual void ConvertToManuallyUpdated ()
{
	this.ForceUpdateDependenciesDeep();
	SpriteManager.ConvertToManuallyUpdated(this);
	TextArialInstance.ConvertToManuallyUpdated();
}
public static void LoadStaticContent (string contentManagerName)
{
	ContentManagerName = contentManagerName;
	#if DEBUG
	if (contentManagerName == FlatRedBallServices.GlobalContentManager)
	{
		HasBeenLoadedWithGlobalContentManager = true;
	}
	else if (HasBeenLoadedWithGlobalContentManager)
	{
		throw new Exception("This type has been loaded with a Global content manager, then loaded with a non-global.  This can lead to a lot of bugs");
	}
	#endif
	if (IsStaticContentLoaded == false)
	{
		IsStaticContentLoaded = true;
		lock (mLockObject)
		{
			if (!mHasRegisteredUnload && ContentManagerName != FlatRedBallServices.GlobalContentManager)
			{
				FlatRedBallServices.GetContentManagerByName(ContentManagerName).AddUnloadMethod("ButtonStaticUnload", UnloadStaticContent);
				mHasRegisteredUnload = true;
			}
		}
		bool registerUnload = false;
		if (!FlatRedBallServices.IsLoaded<AnimationChainList>(@"content/entities/button/animationchainlistfile.achx", ContentManagerName))
		{
			registerUnload = true;
		}
		AnimationChainListFile = FlatRedBallServices.Load<AnimationChainList>(@"content/entities/button/animationchainlistfile.achx", ContentManagerName);
		if (!FlatRedBallServices.IsLoaded<Scene>(@"content/entities/button/scenefile.scnx", ContentManagerName))
		{
			registerUnload = true;
		}
		SceneFile = FlatRedBallServices.Load<Scene>(@"content/entities/button/scenefile.scnx", ContentManagerName);
		MultiplayerTD.Entities.TextArial.LoadStaticContent(contentManagerName);
		if (registerUnload && ContentManagerName != FlatRedBallServices.GlobalContentManager)
		{
			lock (mLockObject)
			{
				if (!mHasRegisteredUnload && ContentManagerName != FlatRedBallServices.GlobalContentManager)
				{
					FlatRedBallServices.GetContentManagerByName(ContentManagerName).AddUnloadMethod("ButtonStaticUnload", UnloadStaticContent);
					mHasRegisteredUnload = true;
				}
			}
		}
		CustomLoadStaticContent(contentManagerName);
	}
}
public static void UnloadStaticContent ()
{
	IsStaticContentLoaded = false;
	mHasRegisteredUnload = false;
	if (AnimationChainListFile != null)
	{
		AnimationChainListFile= null;
	}
	if (SceneFile != null)
	{
		SceneFile.RemoveFromManagers(ContentManagerName != "Global");
		SceneFile= null;
	}
}
public static object GetStaticMember (string memberName)
{
	switch(memberName)
	{
		case  "AnimationChainListFile":
			return AnimationChainListFile;
		case  "SceneFile":
			return SceneFile;
	}
	return null;
}
static VariableState mLoadingState = VariableState.Uninitialized;
public static VariableState LoadingState
{
	get
	{
		return mLoadingState;
	}
	set
	{
		mLoadingState = value;
	}
}
VariableState mCurrentState = VariableState.Uninitialized;
public VariableState CurrentState
{
	get
	{
		return mCurrentState;
	}
	set
	{
		mCurrentState = value;
		switch(mCurrentState)
		{
			case  VariableState.Regular:
				SpriteFrameInstanceCurrentChainName = "Regular";
				break;
			case  VariableState.Pressed:
				SpriteFrameInstanceCurrentChainName = "Pressed";
				break;
			case  VariableState.Disabled:
				SpriteFrameInstanceCurrentChainName = "Disabled";
				break;
			case  VariableState.Hover:
				SpriteFrameInstanceCurrentChainName = "Hover";
				break;
		}
	}
}
public MethodInstruction<Button> InterpolateToState (VariableState stateToInterpolateTo, double secondsToTake)
{
	switch(stateToInterpolateTo)
	{
		case  VariableState.Regular:
			break;
		case  VariableState.Pressed:
			break;
		case  VariableState.Disabled:
			break;
		case  VariableState.Hover:
			break;
	}
	var instruction = new MethodInstruction<Button>(this, "StopStateInterpolation", new object[]{stateToInterpolateTo}, TimeManager.CurrentTime + secondsToTake);
	this.Instructions.Add(instruction);
	return instruction;
}
public void StopStateInterpolation (VariableState stateToStop)
{
	switch(stateToStop)
	{
		case  VariableState.Regular:
			break;
		case  VariableState.Pressed:
			break;
		case  VariableState.Disabled:
			break;
		case  VariableState.Hover:
			break;
	}
	CurrentState = stateToStop;
}
public void InterpolateBetween (VariableState firstState, VariableState secondState, float interpolationValue)
{
	switch(firstState)
	{
		case  VariableState.Regular:
			break;
		case  VariableState.Pressed:
			break;
		case  VariableState.Disabled:
			break;
		case  VariableState.Hover:
			break;
	}
	switch(secondState)
	{
		case  VariableState.Regular:
			break;
		case  VariableState.Pressed:
			break;
		case  VariableState.Disabled:
			break;
		case  VariableState.Hover:
			break;
	}
}
object GetMember (string memberName)
{
	switch(memberName)
	{
	}
	return null;
}

    // DELEGATE START HERE
    

        #region IWindow methods and properties

        public event WindowEvent Click;
		public event WindowEvent SlideOnClick;
        public event WindowEvent Push;
		public event WindowEvent DragOver;

        System.Collections.ObjectModel.ReadOnlyCollection<IWindow> IWindow.Children
        {
            get { throw new NotImplementedException(); }
        }

        bool mEnabled = true;
        bool IWindow.Enabled
        {
            get
            {
                return mEnabled;
            }
            set
            {
                mEnabled = value;
            }
        }

		public bool MovesWhenGrabbed
        {
            get;
            set;
        }

        bool IWindow.GuiManagerDrawn
        {
            get
            {
                return false;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public bool IgnoredByCursor
        {
            get
            {
                return false;
            }
            set
            {
                throw new NotImplementedException();
            }
        }



        public System.Collections.ObjectModel.ReadOnlyCollection<IWindow> FloatingChildren
        {
            get { return null; }
        }

        public FlatRedBall.ManagedSpriteGroups.SpriteFrame SpriteFrame
        {
            get
            {
                return null;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        float IWindow.WorldUnitX
        {
            get
            {
                return Position.X;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        float IWindow.WorldUnitY
        {
            get
            {
                return Position.Y;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        float IWindow.WorldUnitRelativeX
        {
            get
            {
                return RelativePosition.X;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        float IWindow.WorldUnitRelativeY
        {
            get
            {
                return RelativePosition.Y;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        float IWindow.ScaleX
        {
            get;
            set;
        }

        float IWindow.ScaleY
        {
            get;
            set;
        }

        IWindow IWindow.Parent
        {
            get
            {
                return null;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        void IWindow.Activity(Camera camera)
        {

        }

        void IWindow.CallRollOff()
        {
            throw new NotImplementedException();
        }

        void IWindow.CallRollOn()
        {
            throw new NotImplementedException();
        }

        void IWindow.CloseWindow()
        {
            throw new NotImplementedException();
        }

		void IWindow.CallClick()
		{
			if(Click != null)
			{
				Click(this);
			}
		}

        public bool GetParentVisibility()
        {
            throw new NotImplementedException();
        }

        bool IWindow.IsPointOnWindow(float x, float y)
        {
            throw new NotImplementedException();
        }

        public void OnDragging()
        {
			if(DragOver != null)
			{
				DragOver(this);
			}
        }

        public void OnResize()
        {
            throw new NotImplementedException();
        }

        public void OnResizeEnd()
        {
            throw new NotImplementedException();
        }

        public void OnLosingFocus()
        {
            // Do nothing
        }

        public bool OverlapsWindow(IWindow otherWindow)
        {
            return false; // we don't care about this.
        }

        public void SetScaleTL(float newScaleX, float newScaleY)
        {
            throw new NotImplementedException();
        }

        public void SetScaleTL(float newScaleX, float newScaleY, bool keepTopLeftStatic)
        {
            throw new NotImplementedException();
        }

        public virtual void TestCollision(Cursor cursor)
        {
            if (HasCursorOver(cursor))
            {
                cursor.WindowOver = this;


                if (cursor.PrimaryPush)
                {

                    cursor.WindowPushed = this;

                    if (Push != null)
                        Push(this);


					cursor.GrabWindow(this);

                }

                if (cursor.PrimaryClick) // both pushing and clicking can occur in one frame because of buffered input
                {
                    if (cursor.WindowPushed == this)
                    {
                        if (Click != null)
                        {
                            Click(this);
                        }

                        // if (cursor.PrimaryDoubleClick && DoubleClick != null)
                        //   DoubleClick(this);
                    }
					else
					{
						if(SlideOnClick != null)
						{
							SlideOnClick(this);
						}
					}
                }
            }
        }

        void IWindow.UpdateDependencies()
        {
            // do nothing
        }



        #endregion

protected bool mIsPaused;
public override void Pause (InstructionList instructions)
{
	base.Pause(instructions);
	mIsPaused = true;
}
public virtual bool HasCursorOver (Cursor cursor)
{
	if (mIsPaused)
	{
		return false;
	}
	if (!mVisible)
	{
		return false;
	}
	if (LayerProvidedByContainer != null && LayerProvidedByContainer.Visible == false)
	{
		return false;
	}
	if (cursor.IsOn3D(SpriteFrameInstance, LayerProvidedByContainer))
	{
		return true;
	}
	if (TextArialInstance.HasCursorOver(cursor))
	{
		return true;
	}
	return false;
}
public virtual bool WasClickedThisFrame (Cursor cursor)
{
	return cursor.PrimaryClick && HasCursorOver(cursor);
}

    }
	
	
	// Extra classes
	public static class ButtonExtensionMethods
	{
		public static void SetVisible (this PositionedObjectList<Button> list, bool value)
		{
			int count = list.Count;
			for (int i = 0; i < count; i++)
			{
				list[i].Visible = value;
			}
		}
	}
	
}
